home *** CD-ROM | disk | FTP | other *** search
/ Visual Cafe 3 / Visual Cafe 3.ISO / Vcafe / JFC.bin / MacMenuUtilities.java < prev    next >
Text File  |  1998-06-30  |  14KB  |  474 lines

  1. /*
  2.  * @(#)MacMenuUtilities.java    1.2 98/01/30
  3.  *
  4.  * Copyright (c) 1998 Sun Microsystems, Inc. All Rights Reserved.
  5.  *
  6.  * This software is the confidential and proprietary information of Sun
  7.  * Microsystems, Inc. ("Confidential Information").  You shall not
  8.  * disclose such Confidential Information and shall use it only in
  9.  * accordance with the terms of the license agreement you entered into
  10.  * with Sun.
  11.  *
  12.  * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE
  13.  * SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  14.  * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
  15.  * PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR ANY DAMAGES
  16.  * SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING
  17.  * THIS SOFTWARE OR ITS DERIVATIVES.
  18.  *
  19.  */
  20.  
  21. package com.sun.java.swing.plaf.mac;
  22.  
  23. import com.sun.java.swing.*;
  24. import com.sun.java.swing.plaf.UIResource;
  25. import java.awt.Color;
  26. import java.awt.Dimension;
  27. import java.awt.Graphics;
  28. import java.awt.Font;
  29. import java.awt.FontMetrics;
  30. import java.awt.Rectangle;
  31. import java.awt.Component;
  32. import java.awt.Insets;
  33. import java.io.Serializable;
  34.  
  35. /**
  36.  * @version @(#)MacMenuUtils.java    1.0 01/20/98
  37.  * @author Symantec
  38.  */
  39.  
  40. class MacMenuUtilities
  41. {
  42.     static final Insets menuItemMargin = new Insets(0, 2, 0, 2);
  43.     static final Insets menuBarItemMargin = new Insets(2, 4, 2, 4);
  44.  
  45.     static final int widestCommandKeyW = 20;
  46.     static final int menuItemGap = 3;
  47.  
  48.     /* MacComboBoxArrowConstants */
  49.     final static int arrowIconWidth = 7;
  50.  
  51.     final static int anArrowHeight = 4;
  52.     final static int arrowVGap = 2;
  53.     final static int arrowIconHeight = anArrowHeight + arrowVGap + anArrowHeight;
  54.     
  55.     private static final int CHECK = 0;
  56.     private static final int TEXT = 1;
  57.     private static final int ICON = 2;
  58.     private static final int COMMAND = 3;
  59.     private static final int SHORTCUT = 4;
  60.     private static final int ARROW = 5;
  61.     
  62.     private static Icon popupMenuDownScrollerArrowIcon = null;
  63.     private static Icon popupMenuUpScrollerArrowIcon = null;
  64.     private static Icon comboBoxPopupArrowIcon = null;
  65.  
  66.  
  67.     private static abstract class MenuItemIcon implements Icon, UIResource, Serializable {
  68.         final static int menuItemIconWidth = 11;
  69.         final static int menuItemIconHeight = 11;
  70.  
  71.         public int getIconWidth() {
  72.             return menuItemIconWidth;
  73.         }
  74.         
  75.         public int getIconHeight() {
  76.             return menuItemIconHeight;
  77.         }
  78.     }
  79.     
  80.     static Icon getCheckBoxMenuItemIcon() {
  81.         return new MenuItemIcon() {
  82.             public void paintIcon(Component c, Graphics g, int x, int y) {
  83.                 if (((AbstractButton) c).getModel().isSelected()) {
  84.                     g.translate(x, y);
  85.     
  86.                     g.drawLine(1, 5, 2, 5);        // Draw the down stroke
  87.                     g.drawLine(1, 6, 5, 6);
  88.                     g.drawLine(2, 7, 4, 7);
  89.                     g.drawLine(3, 8, 3, 8);
  90.     
  91.                     g.drawLine(5, 5, 9, 1);        // Draw the up stroke
  92.                     g.drawLine(6, 5, 9, 2);
  93.     
  94.                     g.translate(-x, -y);
  95.                 }
  96.             }
  97.         };
  98.     }
  99.  
  100.     static Icon getMenuItemCheckIcon() {
  101.         return new MenuItemIcon() {
  102.             public void paintIcon(Component c, Graphics g, int x, int y) {}
  103.         };
  104.     }
  105.  
  106.     static Icon getMenuArrowIcon() {
  107.         return new MenuItemIcon() {
  108.             public void paintIcon(Component c, Graphics g, int x, int y) {
  109.                 g.translate(x, y);
  110.     
  111.                 g.drawLine(0, 0, 0, 10);
  112.                 g.drawLine(1, 1, 1, 9);
  113.                 g.drawLine(2, 2, 2, 8);
  114.                 g.drawLine(3, 3, 3, 7);
  115.                 g.drawLine(4, 4, 4, 6);
  116.                 g.drawLine(5, 5, 5, 5);
  117.     
  118.                 g.translate(-x, -y);
  119.             }
  120.         };
  121.     }
  122.  
  123.     static Icon menuCommandSymbolIcon = new MenuItemIcon() {
  124.             public void paintIcon(Component c, Graphics g, int x, int y) {
  125.                 g.translate(x, y);
  126.     
  127.                 // Draw the outside edges
  128.                 g.drawLine(2, 1, 3, 1);        // Top of tl cloverleaf
  129.                 g.drawLine(7, 1, 8, 1);        // Top of tr cloverleaf
  130.  
  131.                 g.drawLine(1, 2, 1, 3);        // Left of tl cloverleaf
  132.                 g.drawLine(9, 2, 9, 3);        // Right of tr cloverleaf
  133.  
  134.                 g.drawLine(1, 7, 1, 8);        // Left of bl cloverleaf
  135.                 g.drawLine(9, 7, 9, 8);        // Right of br cloverleaf
  136.  
  137.                 g.drawLine(2, 9, 3, 9);        // Bottom of bl cloverleaf
  138.                 g.drawLine(7, 9, 8, 9);        // Bottom of br cloverleaf
  139.  
  140.                 // Draw the inside edges
  141.                 g.drawLine(4, 2, 4, 8);        // Right of left cloverleaves
  142.                 g.drawLine(6, 2, 6, 8);        // Left of right cloverleaves
  143.  
  144.                 g.drawLine(2, 4, 8, 4);        // Bottom of top cloverleaves
  145.                 g.drawLine(2, 6, 8, 6);        // Top of bottom cloverleaves
  146.     
  147.                 g.translate(-x, -y);
  148.             }
  149.         };
  150.  
  151.  
  152.     static Icon getPopupMenuDownScrollerArrowIcon() {
  153.         if (popupMenuDownScrollerArrowIcon == null)
  154.             popupMenuDownScrollerArrowIcon = new MenuItemIcon() {
  155.                 public void paintIcon(Component c, Graphics g, int x, int y) {
  156.                     g.translate(x, y);
  157.         
  158.                     g.drawLine(0, 3, 10, 3);
  159.                     g.drawLine(1, 4, 9, 4);
  160.                     g.drawLine(2, 5, 8, 5);
  161.                     g.drawLine(3, 6, 7, 6);
  162.                     g.drawLine(4, 7, 6, 7);
  163.                     g.drawLine(5, 8, 5, 8);
  164.         
  165.                     g.translate(-x, -y);
  166.                 }
  167.             };
  168.         
  169.         return popupMenuDownScrollerArrowIcon;
  170.     }
  171.  
  172.     static Icon getPopupMenuUpScrollerArrowIcon() {
  173.         if (popupMenuUpScrollerArrowIcon == null)
  174.             popupMenuUpScrollerArrowIcon = new MenuItemIcon() {
  175.                 public void paintIcon(Component c, Graphics g, int x, int y) {
  176.                     g.translate(x, y);
  177.         
  178.                     g.drawLine(5, 3, 5, 3);
  179.                     g.drawLine(4, 4, 6, 4);
  180.                     g.drawLine(3, 5, 7, 5);
  181.                     g.drawLine(2, 6, 8, 6);
  182.                     g.drawLine(1, 7, 9, 7);
  183.                     g.drawLine(0, 8, 10, 8);
  184.         
  185.                     g.translate(-x, -y);
  186.                 }
  187.             };
  188.         
  189.         return popupMenuUpScrollerArrowIcon;
  190.     }
  191.  
  192.     static Icon getComboBoxPopupArrowIcon() {
  193.         if (comboBoxPopupArrowIcon == null)
  194.             comboBoxPopupArrowIcon = new MenuItemIcon() {
  195.                 public void paintIcon(Component c, Graphics g, int x, int y) {
  196.                     Rectangle bounds = c.getBounds();
  197.             
  198.                     int xOrigin = (bounds.width - arrowIconWidth) / 2;
  199.                     int yOrigin = (bounds.height - arrowIconHeight) / 2;
  200.                     
  201.                     g.translate(xOrigin, yOrigin);
  202.  
  203.                     // Paint the upper arrow
  204.                     g.drawLine(3, 0, 3, 0);
  205.                     g.drawLine(2, 1, 4, 1);
  206.                     g.drawLine(1, 2, 5, 2);
  207.                     g.drawLine(0, 3, 6, 3);
  208.             
  209.                     // Paint the lower arrow
  210.                     g.drawLine(0, 6, 6, 6);
  211.                     g.drawLine(1, 7, 5, 7);
  212.                     g.drawLine(2, 8, 4, 8);
  213.                     g.drawLine(3, 9, 3, 9);
  214.             
  215.                     g.translate(-xOrigin, -yOrigin);
  216.                 }
  217.             };
  218.         
  219.         return comboBoxPopupArrowIcon;
  220.     }
  221.     
  222.     static String calculateMenuItemSizes(    JMenuItem menuItem,
  223.                                             FontMetrics fm,
  224.                                             Icon icon,
  225.                                             Icon checkIcon,
  226.                                             Icon arrowIcon,
  227.                                             KeyStroke shortcut,
  228.                                             Rectangle viewR, 
  229.                                             Rectangle[] itemRects
  230.                                             )
  231.     {
  232.         if ((menuItem.getParent() instanceof JMenuBar) )
  233.         {
  234.             arrowIcon = null;
  235.             shortcut = null;
  236.         }
  237.         else if (arrowIcon != null || (shortcut != null && shortcut.getKeyCode() == 0))
  238.         {
  239.             shortcut = null;
  240.         }
  241.         itemRects[TEXT] = new Rectangle();
  242.         itemRects[ICON] = new Rectangle();
  243.  
  244.         Rectangle allowableViewR = new Rectangle(viewR);
  245.  
  246.         /* Initialize the width and height of the checkIcon bounds rectangle itemRects[CHECK].
  247.          *        adjust the allowableViewR width to compensate
  248.         */
  249.         if (checkIcon != null) {
  250.             itemRects[CHECK] = new Rectangle(checkIcon.getIconWidth(), checkIcon.getIconHeight());
  251.             allowableViewR.width -= (itemRects[CHECK].width + menuItemGap);
  252.         }
  253.  
  254.         /* Initialize the width and height of the arrowIcon bounds rectangle itemRects[ARROW].
  255.          *        adjust the allowableViewR width to compensate
  256.         */
  257.         if (arrowIcon != null) {
  258.             itemRects[ARROW] = new Rectangle(widestCommandKeyW + arrowIcon.getIconWidth(), arrowIcon.getIconHeight());
  259.             allowableViewR.width -= (itemRects[ARROW].width + menuItemGap);
  260.         }
  261.  
  262.         /* Initialize the width of the shortcut bounds rectangles itemRects[COMMAND, SHORTCUT].
  263.          *        adjust the allowableViewR width to compensate
  264.         */
  265.         if (shortcut != null) {
  266.             itemRects[COMMAND] = new Rectangle(MenuItemIcon.menuItemIconWidth, MenuItemIcon.menuItemIconHeight);
  267.             itemRects[SHORTCUT] = new Rectangle(widestCommandKeyW, 0);
  268.             allowableViewR.width -= (itemRects[COMMAND].width + itemRects[SHORTCUT].width + menuItemGap);
  269.         }
  270.  
  271.         // layout the text and icon
  272.         String text = SwingUtilities.layoutCompoundLabel(fm, menuItem.getText(), icon,
  273.                                                 menuItem.getVerticalAlignment(), 
  274.                                                 menuItem.getHorizontalAlignment(),
  275.                                                 menuItem.getVerticalTextPosition(), 
  276.                                                 menuItem.getHorizontalTextPosition(),
  277.                                                 allowableViewR, itemRects[ICON], itemRects[TEXT], 
  278.                                                 menuItemGap);
  279.  
  280.         return text;
  281.     }
  282.  
  283.  
  284.     /** 
  285.     * Compute and return the location of the icons origin, the 
  286.     * location of origin of the text baseline, and a possibly clipped
  287.     * version of the compound labels string.  Locations are computed
  288.     * relative to the viewR rectangle. 
  289.     */
  290.     static String layoutMenuItem(
  291.                                     JMenuItem menuItem,
  292.                                     FontMetrics fm,
  293.                                     Icon icon,
  294.                                     Icon checkIcon,
  295.                                     Icon arrowIcon,
  296.                                     KeyStroke shortcut,
  297.                                     Rectangle viewR,
  298.                                     Rectangle[] itemRects
  299.                                     )
  300.     {
  301.         Insets i = menuItem.getInsets();
  302.         viewR.x += i.left;
  303.         viewR.y += i.top;
  304.         viewR.width -= (i.right + viewR.x);
  305.         viewR.height -= (i.bottom + viewR.y);
  306.         
  307.         String text = MacMenuUtilities.calculateMenuItemSizes(    menuItem,
  308.                                                                 fm,
  309.                                                                 icon,
  310.                                                                 checkIcon,
  311.                                                                 arrowIcon,
  312.                                                                 shortcut,
  313.                                                                 viewR, 
  314.                                                                 itemRects
  315.                                                                 );
  316.         int verticalCenter = (itemRects[ICON].union(itemRects[TEXT])).height / 2;
  317.  
  318.         /* Adjust the location of the checkIcon bounds rectangle itemRects[CHECK].
  319.          *    (Also adjust the starting locations of the TEXT and ICON bounds rectangle itemRects.
  320.         */
  321.         if (itemRects[CHECK] != null) {
  322.             itemRects[CHECK].y = verticalCenter - (itemRects[CHECK].height/2);            // Center it vertically
  323.             itemRects[TEXT].x += (itemRects[CHECK].width + menuItemGap);                // Adjust the TEXT location
  324.             itemRects[ICON].x += (itemRects[CHECK].width + menuItemGap);                // Adjust the ICON location
  325.         }
  326.  
  327.         /* Adjust the location of the arrowIcon bounds rectangle itemRects[ARROW].
  328.         */
  329.         if (itemRects[ARROW] != null) {
  330.             itemRects[ARROW].x = (viewR.x + viewR.width) - itemRects[ARROW].width;
  331.             itemRects[ARROW].y = verticalCenter - (itemRects[ARROW].height/2);            // Center it vertically
  332.         }
  333.  
  334.         /* Adjust the shortcut bounds rectangles itemRects[COMMAND, SHORTCUT].
  335.         */
  336.         if (itemRects[SHORTCUT] != null) {
  337.             itemRects[COMMAND].x = (viewR.x + viewR.width) - (itemRects[COMMAND].width + itemRects[SHORTCUT].width);
  338.             itemRects[COMMAND].y = verticalCenter - (itemRects[COMMAND].height/2);        // Center it vertically
  339.  
  340.             itemRects[SHORTCUT].x = itemRects[COMMAND].x + itemRects[COMMAND].width;    // Locate it to the right of the command key
  341.             itemRects[SHORTCUT].y = itemRects[TEXT].y;                                    // Position it vertically with the text
  342.             itemRects[SHORTCUT].height = itemRects[TEXT].height;
  343.         }
  344.         
  345.         return text;
  346.     }
  347.  
  348.  
  349.     static void paintMenuItem(Graphics g, JMenuItem menuItem,
  350.                                 Icon checkIcon, Icon arrowIcon,
  351.                                 Color background, Color foreground)
  352.     {
  353.         Font font = menuItem.getFont();
  354.         FontMetrics fm = menuItem.getToolkit().getFontMetrics(font);
  355.  
  356.         Rectangle viewRect = new Rectangle(menuItem.getSize());
  357.         Rectangle itemRects[] = new Rectangle[6];
  358.  
  359.         Color holdc = g.getColor();
  360.  
  361.         // Paint the background
  362.         if (background != null) {
  363.             g.setColor(background);
  364.             g.fillRect(0,0, viewRect.width, viewRect.height);
  365.         } else if (menuItem.isOpaque()) {
  366.             g.setColor(menuItem.getBackground());
  367.             g.fillRect(0,0, viewRect.width, viewRect.height);
  368.         }
  369.  
  370.         
  371.         KeyStroke shortcut = menuItem.getAccelerator();
  372.  
  373.         // layout the text and icon
  374.         String text = MacMenuUtilities.layoutMenuItem(
  375.                                                 menuItem, fm,
  376.                                                 menuItem.getIcon(), checkIcon, arrowIcon, shortcut,
  377.                                                 viewRect, itemRects
  378.                                                 );
  379.  
  380.         if (foreground != null) {
  381.             g.setColor(foreground);
  382.         } else {
  383.             g.setColor(menuItem.getForeground());
  384.         }
  385.  
  386.         // Paint the Icon
  387.         if (menuItem.getIcon() != null) { 
  388.             ButtonModel model = menuItem.getModel();
  389.             Icon icon;
  390.             if (!model.isEnabled()) {
  391.                 icon = (Icon) menuItem.getDisabledIcon();
  392.             } else if (model.isPressed() && model.isArmed()) {
  393.                 icon = (Icon) menuItem.getPressedIcon();
  394.                 if(icon == null) {
  395.                     // Use default icon
  396.                     icon = (Icon) menuItem.getIcon();
  397.                 } 
  398.             } else {
  399.                 icon = (Icon) menuItem.getIcon();
  400.             }
  401.  
  402.             icon.paintIcon(menuItem, g, itemRects[ICON].x, itemRects[ICON].y);
  403.         }
  404.  
  405.         // Paint the Check
  406.         if (itemRects[CHECK] != null) {
  407.             checkIcon.paintIcon(menuItem, g, itemRects[CHECK].x, itemRects[CHECK].y);
  408.         }
  409.         
  410.         // Draw the Text
  411.         if (!itemRects[TEXT].isEmpty()) {
  412.             g.drawString(text, itemRects[TEXT].x, itemRects[TEXT].y + fm.getAscent());
  413.         }
  414.         
  415.         // Paint the Arrow
  416.         if (itemRects[ARROW] != null) {
  417.             arrowIcon.paintIcon(menuItem, g, itemRects[ARROW].x + MenuItemIcon.menuItemIconWidth, itemRects[ARROW].y);
  418.         }
  419.  
  420.         // Draw the shortcut
  421.         if (itemRects[SHORTCUT] != null) {
  422.             menuCommandSymbolIcon.paintIcon(menuItem, g, itemRects[COMMAND].x, itemRects[COMMAND].y);
  423.  
  424.             char data[] = new char[] { (char) shortcut.getKeyCode() };
  425.             g.drawChars(data, 0, 1, itemRects[SHORTCUT].x, itemRects[SHORTCUT].y + fm.getAscent());
  426.         }
  427.  
  428.         g.setColor(holdc);
  429.     }
  430.  
  431.  
  432.     static Dimension getPreferredMenuItemSize(JMenuItem menuItem,
  433.                                                 Icon checkIcon,
  434.                                                 Icon arrowIcon)
  435.     {
  436.         Font font = menuItem.getFont();
  437.         FontMetrics fm = menuItem.getToolkit().getFontMetrics(font);
  438.         
  439.         Rectangle viewR = new Rectangle(Short.MAX_VALUE, Short.MAX_VALUE);
  440.         Rectangle itemRects[] = new Rectangle[6];
  441.  
  442.         MacMenuUtilities.calculateMenuItemSizes(
  443.                                             menuItem, fm,
  444.                                             menuItem.getIcon(), checkIcon, arrowIcon, menuItem.getAccelerator(),
  445.                                             viewR, itemRects
  446.                                             );
  447.  
  448.         // find the union of the icon and text rects
  449.         Rectangle r = itemRects[ICON].union(itemRects[TEXT]);
  450.         
  451.         // Add in the checkIcon
  452.         if (itemRects[CHECK] != null) {
  453.             r.width += (itemRects[CHECK].width + menuItemGap);
  454.         }
  455.         
  456.         // Add in the arrowIcon
  457.         if (itemRects[ARROW] != null) {
  458.             r.width += (itemRects[ARROW].width + menuItemGap);
  459.         }
  460.         
  461.         // Add in the shortcut
  462.         if (itemRects[SHORTCUT] != null) {
  463.             r.width += (itemRects[COMMAND].width + itemRects[SHORTCUT].width + menuItemGap);
  464.         }
  465.  
  466.         // Add in the insets
  467.         Insets insets = menuItem.getInsets();
  468.         r.width += insets.left + insets.right;
  469.         r.height += insets.top + insets.bottom;
  470.  
  471.         return r.getSize();
  472.     }
  473. }
  474.